אם אתה יודע את שני הדברים האלה על closures - אתה יכול לקבל גישה למטודות ומאפיינים חבויים של מחלקות. מצד שני, אם אין לך מושג מה זה closure ופונקציות אנונימיות - לא נורא. יש עוד מדריכים מעניינים באתר.
שים לב: הדוגמאות מובאות להרחבת הידע הכללי בלבד. אם אתה מוצא סיבה טובה להשתמש בקוד כזה בפועל - ספר לי בתגובה.
אני הולך לספר לך על דרך מעניינת לקבל גישה למטודות ומאפיינים פרטיים של מחלקות. אבל לפני שאני מראה לך איך בדיוק אפשר לעשות את זה, בו ניישר קו על הדברים הבסיסיים.
פונקציות אנונימיות שעוטפות ערכים (או "סוגרות" ערכים) - נקראות closures.
כדי לסגור ערכים מסוימים - אנחנו מכניסים אותם לבלוק use.
$x = 1;
$addOne = function($p) use ($x) { return $p + $x; };
echo $addOne(5);
$addOne = function($p) use ($x) { return $p + $x; };
echo $addOne(5);
עד כאן אני מקווה שלא הפתעתי אותך וכתבת קוד כזה בעצמך.
ההפתעה הראשונה תהיה עוד משתנה אחד שתמיד נסגר על יד closure גם אם לא רשמת אותו בפירוש בתוך בלוק ה-use. כמה שזה נשמע מפתיע מצד אחד - זה די לגיטימי כשמסתכלים על זה:
closure שנמצא בתוך מחלקה תמיד סוגר את המשתנה $this, כדי שתוכל להשתמש בו בתוך הקלוז'ור
גם אם לא רשמת את זה בפירוש בבלוק use של אותו קלוז'ור. הנא דוגמה:
class my
{
private $increment = 9;
public function GetAddFunc()
{
return function($x) { return $x + $this->increment;};
}
}
$my = new my();
$addFunc = $my->GetAddFunc();
echo $addFunc(1);
{
private $increment = 9;
public function GetAddFunc()
{
return function($x) { return $x + $this->increment;};
}
}
$my = new my();
$addFunc = $my->GetAddFunc();
echo $addFunc(1);
מה לדעתך סוג המשתנה $addFunc ?
אם ענית משהו אחר ממחלקה מסוג Closure - פספסת כמה פסקאות בדוקומנטציה.
מה המשמעוט של מחלקה? זה אומר שיש לה מטודות שאפשר להפעיל. מעניין אילו? בוא נראה:
למחלקה closure מטודה בשם bind שמאפשרת ליצור closure חדש מתוך closure קיים ולחבר אליו $this כלשהו.
class Five { public $num = 5; }
class Six { public $num = 6; }
$five = new Five();
$six = new Six();
// A closure without $this;
$getNum = function() { return $this->num; };
// Copies getNum and Sets $this inside the new closure to be $fiveInstance
$getNum5 = Closure::bind($getNum, $five);
$getNum6 = Closure::bind($getNum, $six);
echo $getNum5(), ' ', $getNum6();
class Six { public $num = 6; }
$five = new Five();
$six = new Six();
// A closure without $this;
$getNum = function() { return $this->num; };
// Copies getNum and Sets $this inside the new closure to be $fiveInstance
$getNum5 = Closure::bind($getNum, $five);
$getNum6 = Closure::bind($getNum, $six);
echo $getNum5(), ' ', $getNum6();
ומטודה נוספת, bindTo שעושה בדיוק אותו דבר, אבל על מופע קיים של closure:
$myInstance = new whatever();
$myClosure = function() {};
// Creates a copy of myClosure and binds it
$newBound = Closure::bind($myClosure, $myInstance);
// Eventually the same as above
$anotherbound = $myClosure->bindTo($myInstance);
$myClosure = function() {};
// Creates a copy of myClosure and binds it
$newBound = Closure::bind($myClosure, $myInstance);
// Eventually the same as above
$anotherbound = $myClosure->bindTo($myInstance);
בצורה כזו אפשר לעשות הרבה דברים מעניינים. למשל יצירה דינמית של מטודות חדשות בתוך מחלקה על הדרך או גישה למאפיינים פרטיים. הנא דוגמא:
class Chocolate
{
private $amount = "15kg";
}
$myChocolate = new Chocolate();
$sweetsThief = function()
{
echo 'There was ', $this->amount, ' but only ';
$this->amount = ($this->amount - 1) . "kg";
echo $this->amount, ' left', PHP_EOL;
};
$goGetMeChocolate = Closure::bind($sweetsThief, $myChocolate, 'Chocolate');
$goGetMeChocolate();
$goGetMeChocolate();
{
private $amount = "15kg";
}
$myChocolate = new Chocolate();
$sweetsThief = function()
{
echo 'There was ', $this->amount, ' but only ';
$this->amount = ($this->amount - 1) . "kg";
echo $this->amount, ' left', PHP_EOL;
};
$goGetMeChocolate = Closure::bind($sweetsThief, $myChocolate, 'Chocolate');
$goGetMeChocolate();
$goGetMeChocolate();
תגובות לכתבה:
אפשר לציין שגישה למאפיינים ומטודות פרטיות ברפלקסיה איטיים פי שניים מקלוז'ורים.
תודה רבה. שימוש מעניין. :)
ההוספה של this לתוך ה-closure כשאתה בתוך מחלקה לא נוספה באחת הגירסאות האחרונות שיצאו? כי זכור לי שפעם הייתה בעיה עם זה. ואם היית עושה use $this אז הייתה שגיאה. ולכן הייתי יוצר משתנה חדש בשם that ששווה ל-this ומשתמש בו ב-closure.
@iiddaannyy
ב PHP 5.4.0
התכוונת שאין סיבה להשתמש ב closure?
שאין סיבה לגשת למאפיינים ומטודות פרטיות של מחלקה